﻿/*
   Copyright 2011 Softisis

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FOM.Impl.Converters;
using FOM.Interfaces;

namespace TestUnits
{

    /// <summary>
    /// Holds a bundle of test utilies
    /// </summary>
    /// <remarks>Copyright Softisis 2011 (France)</remarks>
    public static class TestObjectsHolder {

        public static ObjectA GetObjectA()
        {
            ObjectA a = new ObjectA();
            a.Anid = 123456;

            a.Car = 'c';
            a.Carobject = 'C';
            a.Chaine = "une Chaine";
            a.Doubleobject = 10.233;
            a.Entier = 666;
            a.NullString = null;
            a.UnEnum = MonEnum.UnEnum;
            a.UnObjetB = GetObjectB();

            a.IntTab = new int[2];
            a.IntTab[0] = 12;
            a.IntTab[1] = 13;

            a.UneListe = new System.Collections.ArrayList();
            a.UneListe.Add("xxx");
            a.UneListe.Add(23);

            a.UneListeDeB = new List<ObjectB>();
            a.UneListeDeB.Add(new ObjectB());

            a.UnHashSetDeB = new HashSet<ObjectB>();

            return a;
        }
        
        public static ObjectB GetObjectB()
        {
            var ret=new ObjectB();
            ret.BCar = 'x';
            ret.BChaine = "Chain de B";
            ret.BEntier = 987;
            ret.BUnEnum = MonEnum.UnDeuxiemeEnum;
            return ret;
        }

        /// <summary>
        /// Object with hashset<>
        /// </summary>
        /// <returns></returns>
        public static ObjectC GetObjectC()
        {
            var oc = new ObjectC();
            oc.Val1 = 666;
            oc.Hashset = new HashSet<ObjectA>();
            var oa1 = GetObjectA();
            oc.Hashset.Add(oa1);

            var oa2 = GetObjectA();
            oa2.Chaine = "2eme object A";
            oc.Hashset.Add(oa2);

            // add implementation of objectD
            var tmp = new ObjDImpl1();
            tmp.Str = "789456"; // keep it as a number and use a converter
            tmp.ValX = 654;
            oc.IoD = tmp;

            oc.ob = new ObjectB()
                        {
                            BCar = 't',
                            BCarobject = 'T',
                            BChaine = "BChain2",
                            BDoubleobject = 146.89,
                            BEntier = 333,
                            BNullString = null,
                            BUnEnum = MonEnum.UnDeuxiemeEnum,
                            BUnObjetA = null,
                            BUnobjectC = null
                        };


            return oc;
        }
    }


    public class ObjectA
    {
        public int Anid { get; set; } // ne derait pas etre recopie car c'est un field et non pas une property

        public int Entier { get; set; }
        public Double Doubleobject { get; set; }
        public String Chaine { get; set; }
        public char Car { get; set; }
        public Char Carobject { get; set; }
        public MonEnum UnEnum { get; set; }

        public int[] IntTab { get; set; }

        public String NullString { get; set; }

        public ObjectB UnObjetB { get; set; }

        public IList UneListe { get; set; }

        public IList<ObjectB> UneListeDeB { get; set; }

        public HashSet<ObjectB> UnHashSetDeB { get; set; }

        public override String ToString()
        {
            String ret = "ID:" + Anid + "\n";
            ret += "Entier:" + Entier + "\n";
            ret += "Doubleobject:" + Doubleobject + "\n";
            ret += "Chaine:" + Chaine + "\n";
            ret += "Car:" + Car + "\n";
            ret += "CarObject:" + Carobject + "\n";
            ret += "UnEnum:" + UnEnum + "\n";
            ret += "NullString:" + NullString + "\n";
            ret += "UnObjetB:" + UnObjetB + "\n";

            ret += "IntTab:" + IntTab + "\n";
            return ret;
        }


    }

    public enum MonEnum
    {
        UnEnum = 1,
        UnDeuxiemeEnum = 2
    }



    public class ObjectB
    {

        public int BEntier { get; set; }
        public Double BDoubleobject { get; set; }
        public String BChaine { get; set; }
        public char BCar { get; set; }
        public Char BCarobject { get; set; }
        public MonEnum BUnEnum { get; set; }

        public int RandomVal { get; set; }
        public String BNullString { get; set; }
        public ObjectA BUnObjetA { get; set; }
        public ObjectC BUnobjectC { get; set; }

        public MonEnum? BUnNullableEnum { get; set; }

        public ObjectB()
        {
            Random r=new Random();
            RandomVal = r.Next();
        }

        public override String ToString()
        {
            StringBuilder sb=new StringBuilder();
            sb.Append("BEntier=" + BEntier + "\n");
            sb.Append("BDoubleobject=" + BDoubleobject + "\n");
            sb.Append("BChaine=" + BChaine + "\n");
            sb.Append("BCar=" + BCar + "\n");
            sb.Append("BCarobject=" + BCarobject + "\n");
            sb.Append("BUnEnum=" + BUnEnum + "\n");
            sb.Append("BNullString=" + BNullString + "\n");
            sb.Append("BUnObjetA=" + BUnObjetA + "\n");

            return sb.ToString();
        }
    }
    
    public class ObjectC
    {
        public int Val1 { get; set; }
        public ObjectB ob { get; set; }
        public HashSet<ObjectA> Hashset { get; set; }

        public String CChaine { get; set; }

        /// <summary>
        /// Implementation dependant
        /// </summary>
        public IObjectD IoD { get; set; }
    }


    /// <summary>
    /// Interface with one attribute
    /// </summary>
    public interface IObjectD
    {
        int ValX { get; set; }
    }
    public class ObjDImpl1:IObjectD
    {
        public int ValX { get; set; }
        public string Str { get; set; }
    }
    public class ObjDImpl2 : IObjectD
    {
        public int ValX { get; set; }
        public double Double { get; set; }
    }
    
    /// <summary>
    /// A converter from Impl1 to Impl2 of C
    /// </summary>
    public class Ci1toCi2 : IConverter
    {
        public object Convert(MappingContext ctx)
        {
            var s = ctx.ObjectSrc as ObjDImpl1;
            var d = ctx.ObjectDst as ObjDImpl2;

            if (s==null || d==null)
                throw new Exception("Types in converter are not those expected. Source must be ObjDImpl1 and target ObjDImpl2");

            d.ValX = s.ValX;
            d.Double = int.Parse(s.Str);

            return d;
        }

        public IConverter Reverse()
        {
            return null;
        }
    }




    public class B2AConverver : IConverter
    {
        public object Convert(MappingContext ctx)
        {
            if (ctx.Tsrc!=typeof(ObjectB) || ctx.Tdst!=typeof(ObjectA))
                throw new InvalidCastException("Converter is C to A");
                
            var A = ctx.ObjectDst as ObjectA;
            var B = ctx.ObjectSrc as ObjectB;

            A.Chaine = B.BChaine.ToUpper() + "--converted";
            A.Anid = B.BEntier;
            A.Doubleobject = B.BDoubleobject;
            A.Car = ("" + B.BUnEnum)[0]; // stupid, but for tests

            return ctx.ObjectDst;
        }

        public IConverter Reverse()
        {
            return null;
        }
    }



    // THESE "reverse" OBJECT ARE FOR LIST MAPPING TESTING with cached object
    public class R
    {
        public string name { get; set; }

        public S s { get; set; }
        public int i { get; set; }

        public override string ToString()
        {
            return name;
        }
    }

    public class S
    {
        public string name { get; set; }

        private IList<R> _rr = new List<R>();

        public R[] fixArray { get; set; }

        public IList<R> rlist
        {
            get { return _rr; }
            set { _rr = value; }
        }

        public T t { get; set; }
        public double d { get; set; }
        public override string ToString()
        {
            return name;
        }
    }

    public class T
    {
        public string name { get; set; }

        private IList<S> _ss = new List<S>();
        public IList<S> ss
        {
            get { return _ss; }
            set { _ss = value; }
        }

        public char c { get; set; }
        public override string ToString()
        {
            return name;
        }
    }

    /********* USEFUL for cross reference test/using cache ************/

    public class X
    {
        public X x1 { get; set; }
        public X x2 { get; set; }
        public X x3 { get; set; }

        public Y y1 { get; set; }
        public Y y2 { get; set; }
        public Y y3 { get; set; }


        public int i { get; set; }

    }


    public class Y
    {
        public X x1 { get; set; }
        public X x2 { get; set; }
        public X x3 { get; set; }

        public Y y1 { get; set; }
        public Y y2 { get; set; }
        public Y y3 { get; set; }

        public int j { get; set; }

    }

}
